home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The PC-SIG Library 9
/
The PC-SIG Library on CD ROM - Ninth Edition.iso
/
401_500
/
DISK0432
/
DISK0432.ZIP
/
BUF160.AQM
/
BUF160.ASM
Wrap
Assembly Source File
|
1985-08-16
|
9KB
|
289 lines
PAGE ,132
TITLE BUF160
; MASM 1.25 gave errors on MOV to DD defined words. Fixed by adding
; WORD PTR in appropriate places. Added comments for previous
; versions. Ted Shapin, 2/11/85.
;
; The original version
; improperly handled one of the keyboard service functions (return
; shift key status: interrupt 16, function 2), and would crash
; whenever any program asked for the shift key status. Apparently
; many programs just look this value up for themselves instead of
; going through the BIOS, but Epsilon plays by the rules where
; possible, and calls this function to determine the shift key
; settings.
;
; I've fixed this bug in buf160.asm and am placing these changes in
; the public domain.
;
; This file should be assembled to get buf160.obj, which is
; linked to get buf160.exe, which in turn is run through exe2bin to
; produce buf160.com. Ignore the "missing stack segment" message from
; link.
;
; Steve Doerfler, Lugaru Software, date unknown.
;
; Original by John Socha in Softalk for the IBM PC, Nov. 83. Translated
; to assembler by Jim Gillogly 11/22/83/
;
VECTORS SEGMENT AT 0H
ORG 9H*4
KEYBOARD_INT_VECTOR LABEL DWORD
ORG 16H*4
KEYBOARD_IO_VECTOR LABEL DWORD
VECTORS ENDS
ROM_BIOS_DATA SEGMENT AT 40H
ORG 17H
KBD_FLAG DB ?
ORG 1AH
ROM_BUFFER_HEAD DW ?
ROM_BUFFER_TAIL DW ?
KB_BUFFER DW 16D DUP (?)
KB_BUFFER_END LABEL WORD
ROM_BIOS_DATA ENDS
CODE_SEG SEGMENT
ASSUME CS:CODE_SEG
ORG 100H
BEGIN: JMP INIT_VECTORS ;Initialize vectors and attach to DOS
ROM_KEYBOARD_INT DD 0 ;[0 needed for MS-MASM 3.00 -rag]
ROM_KEYBOARD_IO DD 0
BUFFER_HEAD DW OFFSET KEYBOARD_BUFFER
BUFFER_TAIL DW OFFSET KEYBOARD_BUFFER
KEYBOARD_BUFFER DW 160D DUP(0) ;159 character input buffer
KEYBOARD_BUFFER_END LABEL WORD
;--------------------------------------------------------;
; This procedure sends a short beep when the buffer fills
;--------------------------------------------------------;
KB_CONTROL EQU 61H ;Control bits for keyboard & speaker
ERROR_BEEP PROC NEAR
PUSH AX
PUSH BX
PUSH CX
PUSHF ;Save old interupt enable flag
CLI ;Turn off beep during interupt
MOV BX,30D ;Number of cycles for 1/8 second tone
IN AL,KB_CONTROL ;Get information from speaker port
PUSH AX ;Save control information
START_OF_ONE_CYCLE:
AND AL,0FCH ;Turn off speaker
OUT KB_CONTROL,AL
MOV CX,60D ;Delay for one half cycle
OFF_LOOP:
LOOP OFF_LOOP
OR AL,2 ;Turn off speaker
OUT KB_CONTROL,AL
MOV CX,60D ;Delay for second half cycle
ON_LOOP:
LOOP ON_LOOP
DEC BX ;200 cycles yet?
JNZ START_OF_ONE_CYCLE
POP AX ;Recover old keyboard information
OUT KB_CONTROL,AL
POPF ;Restore interupt flag
POP CX
POP BX
POP AX
RET
ERROR_BEEP ENDP
;This procedure checks the ROM keyboard buffer to see if some program
;tried to clear this buffer. We know it's been cleared when the ROM
;tail and header overlap. Normally, the new procedures below keep the
;dummy character, word 0,in the buffer.
;
;Uses: BX,DS
;Writes: BUFFER_HEAD,BUFFER_TAIL,ROM_BUFFER_HEAD,
; ROM_BUFFER_TAIL
;Reads: KEYBOARD_BUFFER,KB_BUFFER
CHECK_CLEAR_BUFFER PROC NEAR
ASSUME DS:ROM_BIOS_DATA
MOV BX,ROM_BIOS_DATA ;Establish pointer to BIOS data
MOV DS,BX
CLI ;Turn off interupts during this check
MOV BX,ROM_BUFFER_HEAD ;check to see if buffer cleared
CMP BX,ROM_BUFFER_TAIL ;Is the buffer empty?
JNE BUFFER_OK ;No, then everything is alright
;Yes, then clear the internal buffer
MOV BX,OFFSET KB_BUFFER ;Reset buffer with word 0 in buffer
MOV ROM_BUFFER_HEAD,BX
ADD BX,2
MOV ROM_BUFFER_TAIL,BX
ASSUME DS:CODE_SEG
MOV BX,CS
MOV DS,BX
MOV BX,OFFSET KEYBOARD_BUFFER ;Reset internal buffer
MOV BUFFER_HEAD,BX
MOV BUFFER_TAIL,BX
BUFFER_OK:
ASSUME DS:CODE_SEG
STI ;Interupts back on
RET
CHECK_CLEAR_BUFFER ENDP
;This procedure intercepts the keyboard interrupt and moves any new
;characters to the internal, 80 character buffer.
INTERCEPT_KEYBOARD_INT PROC NEAR
ASSUME DS:NOTHING
PUSH DS
PUSH SI
PUSH BX
PUSH AX
CALL CHECK_CLEAR_BUFFER ;Check for buffer cleared
PUSHF
CALL ROM_KEYBOARD_INT ;Read scan code with BIOS routines
;----- Transfer any characters to internal buffer
ASSUME DS:ROM_BIOS_DATA
MOV BX,ROM_BIOS_DATA ;Establish pointer to BIOS data
MOV DS,BX
MOV SI,BUFFER_TAIL
MOV BX,ROM_BUFFER_HEAD ;Check if real characters in buffer
INC BX ;Skip over dummy character
INC BX
CMP BX,OFFSET KB_BUFFER_END
JB DONT_WRAP ;No need to wrap the pointer
MOV BX,OFFSET KB_BUFFER ;Wrap the pointer
DONT_WRAP:
CMP BX,ROM_BUFFER_TAIL ;Is there a real character?
JE NO_NEW_CHARACTERS ;No then return to caller
MOV AX,[BX] ;Yes,move character to internal buffer
MOV CS:[SI],AX
INC SI
INC SI ;Move to next position
CMP SI,OFFSET KEYBOARD_BUFFER_END
JB NOT_AT_END
MOV SI,OFFSET KEYBOARD_BUFFER
NOT_AT_END:
CMP SI,BUFFER_HEAD ;Buffer overrun?
JNE WRITE_TO_BUFFER ;Yes beep and throw out character
CALL ERROR_BEEP
JMP SHORT NOT_AT_KB_END
WRITE_TO_BUFFER:
MOV BUFFER_TAIL,SI
NOT_AT_KB_END:
MOV ROM_BUFFER_HEAD,BX
NO_NEW_CHARACTERS:
;---- See if CTRL + ALT pushed, and clear buffer if so
MOV AL,KBD_FLAG ;Get status of shift keys into AL
AND AL,0CH ;Isolate Alt and Crtl shift flags
CMP AL,0CH ;Are both the Alt and Crtl keys down?
JNE DONT_CLEAR_BUFFER ;No, then dont clear the buffer
MOV AX,BUFFER_TAIL ;Yes, then clear the buffer
MOV BUFFER_HEAD,AX
DONT_CLEAR_BUFFER:
POP AX
POP BX
POP SI
POP DS
IRET
INTERCEPT_KEYBOARD_INT ENDP
;-----------------------------------------------------------------------;
;This procedure replaces the ROM BIOS routines for reading a character ;
;-----------------------------------------------------------------------;
ASSUME DS:CODE_SEG
INTERCEPT_KEYBOARD_IO PROC FAR
STI ;Interrupts back on
PUSH DS ;Save current DS
PUSH BX ;Save BX temporarily
CALL CHECK_CLEAR_BUFFER ;Check for buffer cleared
MOV BX,CS ;Establish pointer to data area
MOV DS,BX
OR AH,AH ;AH=0?
JZ READ_CHARACTER ;Yes, read a character
CMP AH,1 ;AH=1?
JE READ_STATUS ;Yes, return the status
POP BX ;Pass other calls to the rom bios
POP DS
ASSUME DS:NOTHING
JMP ROM_KEYBOARD_IO ;Let ROM routines do this
ASSUME DS:CODE_SEG
;---- Read the key
READ_CHARACTER: ;ASCII read
STI ;Interrupts back on during loop
NOP ;Allow an interrupt to occur
CLI ;Interrupts back off
MOV BX,BUFFER_HEAD ;Get pointer to head of buffer
CMP BX,BUFFER_TAIL ;Test end of buffer
JE READ_CHARACTER ;Loop until something in buffer
MOV AX,[BX] ;Get scan code and ASCII code
ADD BX,2 ;Move to next word in buffer
CMP BX,OFFSET KEYBOARD_BUFFER_END ;At end of buffer?
JNE SAVE_POINTER ;No, continue
MOV BX,OFFSET KEYBOARD_BUFFER ;Yes, reset to buffer start
SAVE_POINTER:
MOV BUFFER_HEAD,BX ;Store value in variable
POP BX
POP DS
IRET ;Return to caller
;---- ASCII status
READ_STATUS:
CLI ;Interrupts off
MOV BX,BUFFER_HEAD ;Get head pointer
CMP BX,BUFFER_TAIL ;If equal (ZF=1) then nothing there
MOV AX,[BX]
STI ;Interrupts back on
POP BX ;Recover registers
POP DS
RET 2 ;Throw away flags
INTERCEPT_KEYBOARD_IO ENDP
;-----------------------------------------------------------------;
;This procedure initializes the interrupt vectors. ;
;-----------------------------------------------------------------;
INIT_VECTORS PROC NEAR
ASSUME DS:VECTORS
PUSH DS ;Save old Data Segment
MOV AX,VECTORS ;Set up the data segment for vectors
MOV DS,AX
CLI ;Dont allow interrupts
MOV AX,WORD PTR KEYBOARD_INT_VECTOR ;Save addresses of BIOS routines
MOV WORD PTR ROM_KEYBOARD_INT,AX
MOV AX,WORD PTR KEYBOARD_INT_VECTOR[2]
MOV WORD PTR ROM_KEYBOARD_INT[2],AX
;Set up new KEYBOARD_INT vector
MOV WORD PTR KEYBOARD_INT_VECTOR,OFFSET INTERCEPT_KEYBOARD_INT
MOV WORD PTR KEYBOARD_INT_VECTOR[2],CS
STI ;Allow interrupts again
;Set up KEYBOARD_IO vector
MOV AX,WORD PTR KEYBOARD_IO_VECTOR
MOV WORD PTR ROM_KEYBOARD_IO,AX
MOV AX,WORD PTR KEYBOARD_IO_VECTOR[2]
MOV WORD PTR ROM_KEYBOARD_IO[2],AX
MOV WORD PTR KEYBOARD_IO_VECTOR,OFFSET INTERCEPT_KEYBOARD_IO
MOV WORD PTR KEYBOARD_IO_VECTOR[2],CS
;Now set up the the kbd buffer, etc.
ASSUME DS:ROM_BIOS_DATA
MOV AX,ROM_BIOS_DATA
MOV DS,AX
CLI ;Dont allow interrupts now
MOV BX,OFFSET KB_BUFFER
MOV ROM_BUFFER_HEAD,BX
MOV WORD PTR [BX],0
ADD BX,2
MOV ROM_BUFFER_TAIL,BX
STI ;Allow interrupts again
MOV DX,OFFSET INIT_VECTORS ;End of resident portions
INT 27H ;Terminate but stay resident
INIT_VECTORS ENDP
CODE_SEG ENDS
END BEGIN